package com.weishuang.account.log;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: LogAspect
 * @Description: controller日志打印
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Pointcut("execution(public * com.weishuang..*.controller..*.*(..)) " +
            "|| execution(public * com.weishuang..*.api..*.*(..))")
    public void pointcutDef() {}

    /**
     * 声明环绕通知
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("pointcutDef()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        log.info("入参打印 URL={}, Method={}, IP={},调用服务={}，请求参数={}", request.getRequestURI(), request.getMethod(), request.getRemoteAddr(),pjp.getSignature().toString(), getArgsJson(pjp));
        long begin = System.nanoTime();
        Object obj = pjp.proceed();
        long end = System.nanoTime();
        log.info("返回值打印 URL={}, Method={}, IP={},调用服务={}，返回参数={},耗时={} 毫秒", request.getRequestURI(), request.getMethod(), request.getRemoteAddr(),pjp.getSignature().toString(), JSON.toJSONString(obj) ,(end - begin) / 1000000);
        return obj;
    }

    @AfterThrowing(pointcut = "pointcutDef()", throwing = "e")
    public void doThrowing(JoinPoint joinPoint, Exception e) {
        log.error("调用服务异常=Exception = {},  Stack Info = {}", e.getMessage(), e);
    }

    private String getArgsJson(ProceedingJoinPoint pjp) {
        String json = "";
        try {
            List args = new ArrayList();
            for (Object arg : pjp.getArgs()) {
                if(arg instanceof ServletRequest || arg instanceof ServletResponse || arg instanceof InputStreamSource){
                    continue;
                }
                args.add(arg);
            }
            json = JSON.toJSONString(args);
        }catch (Exception e){
            log.error("入参打印异常",e);
        }
        return json;
    }

}
